home *** CD-ROM | disk | FTP | other *** search
- /* SPIM S20 MIPS simulator.
- Misc. routines for SPIM.
- Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
-
- SPIM is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- SPIM is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* $Header: /var/home/cs354/.spim/RCS/spim-utils.c,v 1.5 1992/10/12 11:38:15 cs354 Exp $
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include "spim.h"
- #include "inst.h"
- #include "mem.h"
- #include "reg.h"
- #include "sym_tbl.h"
- #ifdef WIN32
- #include "version.h"
- #define DEFAULT_TRAP_HANDLER "traphand.sim"
- #include "y_tab.h"
- #else
- #ifdef MACINTOSH
- #include "version.h"
- #define DEFAULT_TRAP_HANDLER "trap.handler"
- #include "y_tab.h"
- #else
- #include "y.tab.h"
- #endif
- #endif
- #include "data.h"
-
-
- /* Imported functions: */
-
- void initialize_scanner (FILE *);
- int run_spim (mem_addr, register int, int);
- int yylex (void);
- int yyparse (void);
-
- /* Internal functions: */
-
- static void delete_all_breakpoints (void);
- static mem_addr copy_int_to_stack (int n);
- static mem_addr copy_str_to_stack (const char *s);
-
-
- /* Global Variables: */
-
- int bare_machine = 0; /* Non-zero => ignore assembler
- embellishments to bare hardware */
-
- int quiet = 0; /* Non-zero => no message on traps. */
-
- extern char *input_file_name; /* Name of file being parsed */
-
- extern int yylval; /* Value of token from YYLEX */
-
- int message_out = 0, console_out = 0;
-
- mem_addr program_starting_address = 0;
-
- long initial_text_size = TEXT_SIZE;
-
- long initial_data_size = DATA_SIZE;
-
- long initial_data_limit = DATA_LIMIT;
-
- long initial_stack_size = STACK_SIZE;
-
- long initial_stack_limit = STACK_LIMIT;
-
- long initial_k_text_size = K_TEXT_SIZE;
-
- long initial_k_data_size = K_DATA_SIZE;
-
- long initial_k_data_limit = K_DATA_LIMIT;
-
-
-
- /* Initialize or reinitialize the state of the machine. */
-
- void initialize_world (int load_trap_handler)
- {
- /* Allocate the floating point registers */
- if (FGR == NULL)
- FPR = (double *) malloc (16 * sizeof (double));
- /* Allocate the memory */
- make_memory (initial_text_size,
- initial_data_size, initial_data_limit,
- initial_stack_size, initial_stack_limit,
- initial_k_text_size,
- initial_k_data_size, initial_k_data_limit);
- initialize_registers ();
- initialize_symbol_table ();
- k_text_begins_at_point (K_TEXT_BOT);
- k_data_begins_at_point (K_DATA_BOT);
- data_begins_at_point (DATA_BOT);
- text_begins_at_point (TEXT_BOT);
- if (load_trap_handler)
- {
- int old_bare = bare_machine;
-
- bare_machine = 0; /* Trap handler uses extended machine */
- if (read_assembly_file (DEFAULT_TRAP_HANDLER))
- fatal_error ("Cannot read trap handler\n");
- bare_machine = old_bare;
- }
- initialize_scanner (stdin);
- delete_all_breakpoints ();
- program_starting_address = 0;
- sprintf(mess_buff, "SPIM %s\n", SPIM_VERSION);
- write_output (message_out, mess_buff);
- #ifndef MACINTOSH
- /* the mac has a sexier way to present this information */
- write_output (message_out,
- "Copyright 1990-92 by James R. Larus (larus@cs.wisc.edu)\n");
- write_output (message_out,
- "Modified to read SAL code by Scott Kempf (scottk@cs.wis.edu)\n");
- write_output (message_out, "See the file COPYING for license information\n");
- #endif
- }
-
-
-
- void initialize_registers (void)
- {
- bzero (FPR, 16 * sizeof (double));
- FGR = (float *) FPR;
- FWR = (int *) FPR;
- bzero (R, 32 * sizeof (reg_word));
- R[29] = STACK_TOP - BYTES_PER_WORD - 4096; /* Initialize $sp */
- PC = 0;
- Cause = 0;
- EPC = 0;
- Status_Reg = 0;
- BadVAddr = 0;
- Context = 0;
- PRId = 0;
- }
-
-
- /* Read file NAME, which should contain assembly code. Return zero if
- successful and non-zero otherwise. */
-
- int read_assembly_file (char *name)
- {
- FILE *file = fopen (name, "r");;
-
- source_file = 1;
- if (file == NULL)
- {
- sprintf(mess_buff, "Cannot open file: `%s'\n", name);
- error (mess_buff);
- return (1);
- }
- else
- {
- #ifdef mips
- #include <sys/exec.h>
- unsigned short magic;
-
- fread (&magic, sizeof (short), 1, file);
- fclose (file);
- if (magic == MIPSEBMAGIC || magic == MIPSELMAGIC)
- {
- sprintf(mess_buff, "Source file appears to be executable: %s\n",
- name);
- error (mess_buff);
- return (1);
- }
- fopen (name, "r");
- #endif
- input_file_name = name;
- initialize_scanner (file);
- while (yyparse ()) ;
- fclose (file);
- flush_local_labels ();
- return (0);
- }
- }
-
-
- mem_addr starting_address (void)
- {
- if (PC == 0)
- {
- if (program_starting_address)
- return (program_starting_address);
- else {
- program_starting_address = find_symbol_address (DEFAULT_RUN_LOCATION);
- if (program_starting_address == 0) {
- sprintf(mess_buff, "Program starting label undefined (%s)\n",
- DEFAULT_RUN_LOCATION);
- error(mess_buff);
- program_starting_address = TEXT_BOT;
- }
- return program_starting_address;
- }
- }
- else
- return (PC);
- }
-
-
- /* Initialize the SPIM stack with ARGC, ARGV, and ENVP data. */
-
- void initialize_run_stack (int argc, const char **argv)
- {
- char **p;
- #ifndef MACINTOSH
- extern char **environ;
- #endif
- int i, j = 0, env_j;
- mem_addr addrs[10000];
-
- /* Put strings on stack: */
- #ifndef MACINTOSH
- for (p = environ; *p != '\0'; p++)
- addrs[j++] = copy_str_to_stack (*p);
- #endif
-
- R[REG_A1] = R[29];
- env_j = j;
- for (i = 0; i < argc; i++)
- addrs[j++] = copy_str_to_stack (argv[i]);
-
- R[29] -= 4; /* Leave rest of word empty */
- R[29] = R[29] & 0xfffffff8; /* Round down to double word boundary */
- /* Build vectors on stack: */
- for (i = env_j - 1; i >= 0; i--)
- copy_int_to_stack (addrs[i]);
- for (i = j - 1; i >= env_j; i--)
- copy_int_to_stack (addrs[i]);
-
- R[29] = copy_int_to_stack (argc); /* Leave pointing to argc */
- R[29] = R[29] & 0xfffffff8; /* Round down to double word boundary */
- }
-
-
- static mem_addr copy_str_to_stack (const char *s)
- {
- mem_addr str_start;
- int i = strlen (s);
-
- while (i >= 0)
- {
- SET_MEM_BYTE (R[29], s[i]);
- R[29] -= 1;
- i -= 1;
- }
- str_start = (mem_addr) R[29] + 1;
- R[29] = R[29] & 0xfffffff8; /* Round down to double word boundary */
- return (str_start);
- }
-
-
- static mem_addr copy_int_to_stack (int n)
- {
- SET_MEM_WORD (R[29], n);
- R[29] -= BYTES_PER_WORD;
- return ((mem_addr) R[29] + BYTES_PER_WORD);
- }
-
-
- /* Run a program starting at PC for N steps and display each
- instruction before executing if FLAG is non-zero. If CONTINUE is
- non-zero, then step through a breakpoint. Return non-zero if
- breakpoint is encountered. */
-
- int run_program (mem_addr pc, int steps, int display, int cont_bkpt)
- {
- if (cont_bkpt && inst_is_breakpoint (pc))
- {
- mem_addr addr = PC;
-
- delete_breakpoint (addr);
- exception_occurred = 0;
- run_spim (addr, 1, display);
- add_breakpoint (addr);
- steps -= 1;
- pc = PC;
- }
-
- exception_occurred = 0;
- if (!run_spim (pc, steps, display))
- /* Can't restart program */
- PC = 0;
- if (exception_occurred && Cause == (BKPT_EXCPT << 2))
- return (1);
- else
- return (0);
- }
-
-
- /* Record of where a breakpoint was placed and the instruction previously
- in memory. */
-
- typedef struct bkptrec
- {
- mem_addr addr;
- instruction *inst;
- struct bkptrec *next;
- } bkpt;
-
-
- static bkpt *bkpts = NULL;
-
-
- /* Set a breakpoint at memory location ADDR. */
-
- void add_breakpoint (mem_addr addr)
- {
- bkpt *rec = (bkpt *) malloc (sizeof (bkpt));
-
- rec->next = bkpts;
- rec->addr = addr;
-
- if ((rec->inst = set_breakpoint (addr)) != NULL)
- bkpts = rec;
- else
- {
- if (exception_occurred) {
- sprintf(mess_buff, "Cannot put a breakpoint at address 0x%08x\n",
- addr);
- error (mess_buff);
- }
- else {
- sprintf(mess_buff, "Already have a breakpoint at address 0x%08x\n",
- addr);
- error (mess_buff);
- }
- free (rec);
- }
- }
-
-
- /* Delete all breakpoints at memory location ADDR. */
-
- void delete_breakpoint (mem_addr addr)
- {
- bkpt *p, *b;
- int deleted_one = 0;
-
- for (p = NULL, b = bkpts; b != NULL; )
- if (b->addr == addr)
- {
- bkpt *n;
-
- SET_MEM_INST (addr, b->inst);
- if (p == NULL)
- bkpts = b->next;
- else
- p->next = b->next;
- n = b->next;
- free (b);
- b = n;
- deleted_one = 1;
- }
- else
- p = b, b = b->next;
- if (!deleted_one) {
- sprintf(mess_buff, "No breakpoint to delete at 0x%08x\n", addr);
- error (mess_buff);
- }
- }
-
-
- static void delete_all_breakpoints (void)
- {
- bkpt *b, *n;
-
- for (b = bkpts, n = NULL; b != NULL; b = n)
- {
- n = b->next;
- free (b);
- }
- bkpts = NULL;
- }
-
-
- /* List all breakpoints. */
-
- void list_breakpoints (void)
- {
- bkpt *b;
-
- if (bkpts) {
- for (b = bkpts; b != NULL; b = b->next) {
- sprintf(mess_buff, "Breakpoint at 0x%08x\n", b->addr);
- write_output (message_out, mess_buff);
- }
- }
- else {
- write_output (message_out, "No breakpoints set\n");
- }
- }
-
-
-
- /* Utility routines */
-
- /* Print the error message then exit. */
-
- void fatal_error (char *string)
- {
- #ifdef MACINTOSH
- MacFatalError(string);
- #else
- fprintf (stderr, "%s", string);
- exit (-1);
- /*NOTREACHED*/
- #endif
- }
-
-
- /* Return the entry in the hash TABLE of length LENGTH with key STRING.
- Return NULL if no such entry exists. */
-
- inst_info * map_string_to_inst_info (register inst_info tbl[], int tbl_len,
- register char *id)
- {
- register int low = 0;
- register int hi = tbl_len - 1;
-
- while (low <= hi)
- {
- register int mid = (low + hi) / 2;
- register char *idp = id, *np = tbl[mid].name;
-
- while (*idp == *np && *idp != '\0') {idp ++; np ++;}
-
- if (*np == '\0' && *idp == '\0') /* End of both strings */
- return (& tbl[mid]);
- else if (*idp > *np)
- low = mid + 1;
- else
- hi = mid - 1;
- }
-
- return NULL;
- }
-
-
- /* Return the entry in the hash TABLE of length LENGTH with VALUE1 field NUM.
- Return NULL if no such entry exists. */
-
- inst_info *map_int_to_inst_info (register inst_info tbl[], int tbl_len,
- register int num)
- {
- register int low = 0;
- register int hi = tbl_len - 1;
-
- while (low <= hi)
- {
- register int mid = (low + hi) / 2;
-
- if (tbl[mid].value1 == num)
- return (&tbl[mid]);
- else if (num > tbl[mid].value1)
- low = mid + 1;
- else
- hi = mid - 1;
- }
-
- return NULL;
- }
-
-
- #ifdef NEED_STRTOL
- long strtol (char *str, char *eptr, int base)
- {
- long result;
-
- if (base != 16)
- fatal_error ("SPIM's strtol only works for base 16");
- if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X'))
- str += 2;
- sscanf (str, "%lx", &result);
- return (result);
- }
- #endif
-